/*    file: MultipartBody.cpp
 *    desc:
 * 
 * created: 2017-10-25
 *  author: chuanjiang.zh@qq.com
 * company: 
 */

#include "MultipartBody.h"
#include "TStringUtil.h"
#include "Path.h"
#include "TFileUtil.h"

size_t MultipartBody::Part::getBytes() const
{
	size_t bytes = 0;
	bytes += type.length();
	bytes += data.length();

	StringMap::const_iterator it = header.begin();
	for (; it != header.end(); ++it)
	{
		bytes += it->first.length();
		bytes += it->second.length();
	}
	return bytes;
}

MultipartBody::MultipartBody()
{
	m_boundary = makeBoundary();
}

MultipartBody::~MultipartBody()
{
}

const std::string& MultipartBody::boundary() const
{
	return m_boundary;
}

bool MultipartBody::add(const StringMap& header, const std::string& type, const std::string& data)
{
	if (header.empty())
	{
		return false;
	}

	Part part;
	part.header = header;
	part.type = type;
	part.data = data;

	m_parts.push_back(part);
	return true;
}

bool MultipartBody::addFormData(const std::string& name, const std::string& data)
{
	StringMap header;
	header["name"] = name;
	return add(header, std::string(), data);
}

bool MultipartBody::addFile(const std::string& name, const std::string& type, const std::string& filepath)
{
	std::string data;
	if (!loadFile(filepath, data))
	{
		return false;
	}

	StringMap header;
	header["name"] = name;
	header["filename"] = comn::Path::getFileName(filepath);
	return add(header, type, data);
}

std::string MultipartBody::get()
{
	std::string hyphen = "--";
	std::string endOfLine = "\r\n";
	std::string boundary = hyphen + m_boundary;

	std::string body;
	
	size_t bytes = 0;
	for (size_t i = 0; i < m_parts.size(); i++)
	{
		bytes += m_parts[i].getBytes();
	}

	body.reserve(bytes * 2);

	for (size_t i = 0; i < m_parts.size(); i++)
	{
		if (i == 0)
		{
			body += boundary;
			body += endOfLine;
		}
		else
		{
			body += endOfLine;
			body += boundary;
			body += endOfLine;
		}
		
		makeMessage(m_parts[i], body);
	}

	body += endOfLine;
	body += boundary;
	body += hyphen;
	body += endOfLine;

	return body;
}

void MultipartBody::makeMessage(const Part& part, std::string& data)
{
	/// Content-Disposition
	data += "Content-Disposition: form-data;";

	size_t count = 0;
	StringMap::const_iterator itName = part.header.find("name");
	if (itName != part.header.end())
	{
		data += " ";
		data += itName->first;
		data += "=\"";
		data += itName->second;
		data += "\"";
		count ++;
	}

	StringMap::const_iterator it = part.header.begin();
	for (; it != part.header.end(); ++it)
	{
		if (it == itName)
		{
			continue;
		}

		if (count == 0)
		{
			data += " ";
		}
		else
		{
			data += "; ";
		}
		
		data += it->first;
		data += "=\"";
		data += it->second;
		data += "\"";
	}
	data += "\r\n";

	if (part.type.size() > 0)
	{
		data += "Content-Type: ";
		data += part.type;
		data += "\r\n";
	}

	data += "\r\n";
	data += part.data;
}

std::string MultipartBody::makeBoundary()
{
	//return "---------------------------323691455027319";
	return comn::StringUtil::format("---------------------------%s", this);
}

bool MultipartBody::loadFile(const std::string& filepath, std::string& data)
{
	return comn::FileUtil::load(data, filepath.c_str());
}
